package club.xcgame520.okhttp;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

/**
 * OkHttp
 * <br/>
 * Created by 小灿 on 2016/11/11.
 */

public class OkHttp {

    private static final int CALL_FAILURE = 11;
    private static final int CALL_RESPONSE_SUCCESS = 22;
    private static final int CALL_RESPONSE_FAILURE = 33;
    private static final int CALL_CANCEL = 44;
    private static final int CALL_RESPONSE_PATH = 66;
    private static final int CALL_RESPONSE_PROGRESS = 77;

    public static final String TAG = "OkHttp";
    public static boolean isPrintLog = true;

    private OkHttpClient client;

    private Context context;

    public OkHttp(Context context) {
        this(context, 5, 15, 15);
    }

    /**
     * @param connectTimeout 连接超时（秒钟）
     */
    public OkHttp(Context context, int connectTimeout, int readTimeout, int writeTimeout) {

        this.context = context;

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(connectTimeout, TimeUnit.SECONDS);
        builder.readTimeout(readTimeout, TimeUnit.SECONDS);
        builder.writeTimeout(writeTimeout, TimeUnit.SECONDS);
        client = builder.build();
    }

    /**
     * OkHttp 请求自签名的https初始化
     *
     * @param connectTimeout
     * @param readTimeout
     * @param writeTimeout
     * @param sslSocketFactory
     * @param x509TrustManager
     */
    public OkHttp(Context context, int connectTimeout, int readTimeout, int writeTimeout, SSLSocketFactory sslSocketFactory, X509TrustManager x509TrustManager) {

        this.context = context;

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(connectTimeout, TimeUnit.SECONDS);
        builder.readTimeout(readTimeout, TimeUnit.SECONDS);
        builder.writeTimeout(writeTimeout, TimeUnit.SECONDS);
        // 运行请求重定向
        builder.followRedirects(true);
        // https支持
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        builder.sslSocketFactory(sslSocketFactory, x509TrustManager);
        client = builder.build();

    }

    /**
     * get请求（同时能请求很多个）
     *
     * @param url      请求url
     * @param callback 请求返回回调
     * @return
     */
    public Call get(String url, final ResponseCallback callback) {
        return get(url, null, callback);
    }


    /**
     * get请求（同时能请求很多个）
     *
     * @param url       请求url
     * @param headerMap 头信息key-value
     * @param callback  请求返回回调
     * @return
     */
    public Call get(String url, Map<String, Object> headerMap, final ResponseCallback callback) {
        return get(url, headerMap, null, callback);
    }


    /**
     * get请求（同时能请求很多个）
     *
     * @param url       请求url
     * @param headerMap 头信息key-value
     * @param callback  请求返回回调
     * @return
     */
    public Call get(String url, Map<String, Object> headerMap, Map<String, Object> paramMap, final ResponseCallback callback) {

        if (paramMap != null && paramMap.size() > 0) {
            url = url + "?";
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                url = url + entry.getKey() + "=" + String.valueOf(entry.getValue());
                url = url + "&";
            }
            url = url.substring(0, url.length() - 1);
        }

        callback.setContext(context);
        callback.setUrl(url);

        final Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context == null) {
                    return;
                }
                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    Map<String, Object> response = new HashMap<>();
                    response.put("code", 0);
                    response.put("message", "call failure");
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        if (headerMap != null) {
            for (Map.Entry<String, Object> entry : headerMap.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        Request request = requestBuilder.build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {

                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                Map<String, Object> responseMap = new HashMap<>();
                responseMap.put("code", response.code());
                responseMap.put("message", response.message());
                if (response.body() != null) {
                    responseMap.put("body", response.body().string());
                }
                Message message = handler.obtainMessage();
                if (response.isSuccessful()) {
                    message.what = CALL_RESPONSE_SUCCESS;
                } else {
                    message.what = CALL_RESPONSE_FAILURE;
                }
                message.obj = responseMap;
                handler.sendMessage(message);

            }

        });

        callback.onStart();
        return call;
    }


    /**
     * post请求 (同时能请求很多个) 表单
     *
     * @param url      请求url
     * @param paramMap 请求参数key-value
     * @param callback 请求返回回调
     * @return
     */
    public Call post(String url, Map<String, Object> paramMap, final ResponseCallback callback) {
        return post(url, null, paramMap, callback);
    }


    /**
     * post请求 (同时能请求很多个) 表单
     *
     * @param url       请求url
     * @param headerMap 头信息key-value
     * @param paramMap  请求参数key-value
     * @param callback  请求返回回调
     * @return
     */
    public Call post(String url, Map<String, Object> headerMap, Map<String, Object> paramMap, final ResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        if (OkHttp.isPrintLog) {
            if (paramMap != null) {
                Log.d(OkHttp.TAG, "网络请求：" + url);
                Log.d(OkHttp.TAG, "网络请求参数：" + paramMap.toString());
            }
        }

        final Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context == null) {
                    return;
                }
                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    Map<String, Object> response = new HashMap<>();
                    response.put("code", 0);
                    response.put("message", "call failure");
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        if (headerMap != null) {
            for (Map.Entry<String, Object> entry : headerMap.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        FormBody.Builder bodyBuilder = new FormBody.Builder();
        if (paramMap != null) {
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                bodyBuilder.add(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        requestBuilder.post(bodyBuilder.build());
        Request request = requestBuilder.build();

        final Call call = client.newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {

                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                Map<String, Object> responseMap = new HashMap<>();
                responseMap.put("code", response.code());
                responseMap.put("message", response.message());
                if (response.body() != null) {
                    responseMap.put("body", response.body().string());
                }
                Message message = handler.obtainMessage();
                if (response.isSuccessful()) {
                    message.what = CALL_RESPONSE_SUCCESS;
                } else {
                    message.what = CALL_RESPONSE_FAILURE;
                }
                message.obj = responseMap;
                handler.sendMessage(message);

            }
        });

        callback.onStart();
        return call;
    }


    /**
     * post请求 (同时能请求很多个) 自定义
     *
     * @param url       请求url
     * @param mediaType
     * @param body
     * @param callback  请求返回回调
     * @return
     */
    public Call post(String url, MediaType mediaType, String body, final ResponseCallback callback) {
        return post(url, null, mediaType, body, callback);
    }

    /**
     * post请求 (同时能请求很多个) 自定义
     *
     * @param url       请求url
     * @param headerMap
     * @param mediaType
     * @param body
     * @param callback  请求返回回调
     * @return
     */
    public Call post(String url, Map<String, Object> headerMap, MediaType mediaType, String body, final ResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        final Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context == null) {
                    return;
                }
                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    Map<String, Object> response = new HashMap<>();
                    response.put("code", 0);
                    response.put("message", "call failure");
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        if (headerMap != null) {
            for (Map.Entry<String, Object> entry : headerMap.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        RequestBody requestBody = RequestBody.create(mediaType, body);
        requestBuilder.post(requestBody);
        Request request = requestBuilder.build();

        final Call call = client.newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {

                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                Map<String, Object> responseMap = new HashMap<>();
                responseMap.put("code", response.code());
                responseMap.put("message", response.message());
                if (response.body() != null) {
                    responseMap.put("body", response.body().string());
                }
                Message message = handler.obtainMessage();
                if (response.isSuccessful()) {
                    message.what = CALL_RESPONSE_SUCCESS;
                } else {
                    message.what = CALL_RESPONSE_FAILURE;
                }
                message.obj = responseMap;
                handler.sendMessage(message);

            }
        });

        callback.onStart();
        return call;
    }

    /**
     * 上传单个文件
     *
     * @param url      请求url
     * @param fileName 上传文件的参数名
     * @param file     上传的文件
     * @param callback 请求返回回调
     * @return
     */
    public Call uploadFile(String url, final String fileParam, final String fileName, final File file, final UploadResponseCallback callback) {
        return uploadFile(url, null, null, fileParam, fileName, file, callback);
    }

    /**
     * 上传单个文件
     *
     * @param url      请求url
     * @param fileName 上传文件的参数名
     * @param file     上传的文件
     * @param callback 请求返回回调
     * @return
     */
    public Call uploadFile(String url, Map<String, Object> paramMap, final String fileParam, final String fileName, final File file, final UploadResponseCallback callback) {
        return uploadFile(url, null, paramMap, fileParam, fileName, file, callback);
    }

    /**
     * 上传单个文件
     *
     * @param url      请求url
     * @param fileName 上传文件的参数名
     * @param file     上传的文件
     * @param callback 请求返回回调
     * @return
     */
    public Call uploadFile(String url, Map<String, Object> headerMap, Map<String, Object> paramMap, final String fileParam, final String fileName, final File file, final UploadResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        final Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context == null) {
                    return;
                }
                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    Map<String, Object> response = new HashMap<>();
                    response.put("code", 0);
                    response.put("message", "call failure");
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_RESPONSE_PROGRESS) {
                    Map<String, Object> progressMap = (Map<String, Object>) msg.obj;
                    callback.onProgress(Integer.parseInt(String.valueOf(progressMap.get("progress"))), String.valueOf(progressMap.get("paramKey")), String.valueOf(progressMap.get("fileName")));
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);

        if (file != null && file.exists()) {
            RequestBody requestBody = new RequestBody() {
                @Override
                public MediaType contentType() {
                    return MultipartBody.FORM;
                }

                @Override
                public long contentLength() {
                    return file.length();
                }

                @Override
                public void writeTo(BufferedSink sink) throws IOException {
                    Source source = null;
                    Buffer buf = null;
                    try {
                        source = Okio.source(file);
                        buf = new Buffer();
                        int lastProgress = 0;
                        long remaining = contentLength();
                        for (long readCount; (readCount = source.read(buf, 1024)) != -1; ) {
                            sink.write(buf, readCount);
                            remaining = remaining - readCount;
                            double complete = contentLength() - remaining;
                            int progress = (int) (1d * complete / contentLength() * 100);
                            if (lastProgress != progress) {
                                lastProgress = progress;
                                Message message = handler.obtainMessage();
                                Map<String, Object> progressMap = new HashMap<>();
                                progressMap.put("paramKey", fileParam);
                                progressMap.put("fileName", fileName);
                                progressMap.put("progress", progress);
                                message.obj = progressMap;
                                handler.sendMessage(message);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (source != null) {
                            source.close();
                        }
                        if (buf != null) {
                            buf.close();
                        }
                    }
                }
            };
            builder.addFormDataPart(fileParam, fileName, requestBody);
        }

        if (paramMap != null) {
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                builder.addFormDataPart(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }

        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        if (headerMap != null) {
            for (Map.Entry<String, Object> entry : headerMap.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        requestBuilder.post(builder.build());

        final Call call = client.newCall(requestBuilder.build());

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Map<String, Object> responseMap = new HashMap<>();
                responseMap.put("code", response.code());
                responseMap.put("message", response.message());
                if (response.body() != null) {
                    responseMap.put("body", response.body().string());
                }
                Message message = handler.obtainMessage();
                if (response.isSuccessful()) {
                    message.what = CALL_RESPONSE_SUCCESS;
                } else {
                    message.what = CALL_RESPONSE_FAILURE;
                }
                message.obj = responseMap;
                handler.sendMessage(message);
            }
        });

        callback.onStart();
        return call;

    }

    /**
     * 上传多个文件
     *
     * @param url
     * @param fileParamMap
     * @param callback
     * @return
     */
    public Call uploadFile(String url, Map<String, Map<String, File>> fileParamMap, final UploadResponseCallback callback) {
        return uploadFile(url, null, null, fileParamMap, callback);
    }

    /**
     * 上传多个文件
     *
     * @param url
     * @param paramMap
     * @param fileParamMap
     * @param callback
     * @return
     */
    public Call uploadFile(String url, Map<String, Object> paramMap, Map<String, Map<String, File>> fileParamMap, final UploadResponseCallback callback) {
        return uploadFile(url, null, paramMap, fileParamMap, callback);
    }

    /**
     * 上传多个文件
     *
     * @param url
     * @param headerMap
     * @param paramMap
     * @param fileParamMap
     * @param callback
     * @return
     */
    public Call uploadFile(String url, Map<String, Object> headerMap, Map<String, Object> paramMap, Map<String, Map<String, File>> fileParamMap, final UploadResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        final Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context == null) {
                    return;
                }
                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    Map<String, Object> response = new HashMap<>();
                    response.put("code", 0);
                    response.put("message", "call failure");
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_RESPONSE_PROGRESS) {
                    Map<String, Object> progressMap = (Map<String, Object>) msg.obj;
                    callback.onProgress(Integer.parseInt(String.valueOf(progressMap.get("progress"))), String.valueOf(progressMap.get("paramKey")), String.valueOf(progressMap.get("fileName")));
                }
                if (msg.what == CALL_RESPONSE_SUCCESS) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    Map<String, Object> response = (Map<String, Object>) msg.obj;
                    callback.onFinish();
                    callback.onFailure(response);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };

        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder();
        bodyBuilder.setType(MultipartBody.FORM);

        if (paramMap != null) {
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                bodyBuilder.addFormDataPart(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }

        if (fileParamMap != null) {

            for (Map.Entry<String, Map<String, File>> entry : fileParamMap.entrySet()) {

                final String paramKey = entry.getKey();
                Map<String, File> fileMap = entry.getValue();

                for (Map.Entry<String, File> entry1 : fileMap.entrySet()) {

                    final String fileName = entry1.getKey();
                    final File file = entry1.getValue();

                    if (file != null && file.exists()) {

                        RequestBody requestBody = new RequestBody() {

                            @Override
                            public MediaType contentType() {
                                return MediaType.parse("*/*");
                            }

                            @Override
                            public long contentLength() {
                                return file.length();
                            }

                            @Override
                            public void writeTo(BufferedSink sink) throws IOException {
                                Source source = null;
                                Buffer buf = null;
                                try {
                                    source = Okio.source(file);
                                    buf = new Buffer();

                                    int lastProgress = 0;
                                    long remaining = contentLength();
                                    long readCount;

                                    while ((readCount = source.read(buf, 1024)) != -1) {

                                        sink.write(buf, readCount);
                                        remaining = remaining - readCount;
                                        long complete = contentLength() - remaining;
                                        int progress = (int) (1d * complete / contentLength() * 100);
                                        if (lastProgress != progress) {
                                            lastProgress = progress;
                                            Message message = handler.obtainMessage();
                                            message.what = CALL_RESPONSE_PROGRESS;
                                            Map<String, Object> progressMap = new HashMap<>();
                                            progressMap.put("paramKey", paramKey);
                                            progressMap.put("fileName", fileName);
                                            progressMap.put("progress", progress);
                                            message.obj = progressMap;
                                            handler.sendMessage(message);
                                        }

                                    }

                                } catch (Exception e) {
                                    e.printStackTrace();
                                } finally {
                                    if (source != null) {
                                        source.close();
                                    }
                                    if (buf != null) {
                                        buf.close();
                                    }
                                }
                            }
                        };

                        bodyBuilder.addFormDataPart(paramKey, fileName, requestBody);

                    }

                }

            }

        }

        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        if (headerMap != null) {
            for (Map.Entry<String, Object> entry : headerMap.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        requestBuilder.post(bodyBuilder.build());

        final Call call = client.newCall(requestBuilder.build());

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {

                if (call.isCanceled()) {
                    handler.sendEmptyMessage(CALL_CANCEL);
                } else {
                    handler.sendEmptyMessage(CALL_FAILURE);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Map<String, Object> responseMap = new HashMap<>();
                responseMap.put("code", response.code());
                responseMap.put("message", response.message());
                if (response.body() != null) {
                    responseMap.put("body", response.body().string());
                }
                Message message = handler.obtainMessage();
                if (response.isSuccessful()) {
                    message.what = CALL_RESPONSE_SUCCESS;
                } else {
                    message.what = CALL_RESPONSE_FAILURE;
                }
                message.obj = responseMap;
                handler.sendMessage(message);
            }
        });

        callback.onStart();
        return call;

    }


    /**
     * 下载文件
     *
     * @param url      请求url
     * @param callback 请求返回回调
     */
    public Call downloadFile(String url, final String saveFilePath, final DownloadResponseCallback callback) {

        callback.setContext(context);
        callback.setUrl(url);

        final Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                if (context == null) {
                    return;
                }
                if (context instanceof Activity) {
                    Activity activity = (Activity) context;
                    if (activity.isFinishing()) {
                        return;
                    }
                }
                if (msg.what == CALL_FAILURE) {
                    callback.onFinish();
                    callback.onFailure(0);
                }
                if (msg.what == CALL_RESPONSE_PROGRESS) {
                    int response = (int) msg.obj;
                    callback.onProgress(response);
                }
                if (msg.what == CALL_RESPONSE_PATH) {
                    String response = (String) msg.obj;
                    callback.onFinish();
                    callback.onSuccess(response);
                }
                if (msg.what == CALL_RESPONSE_FAILURE) {
                    int code = (int) msg.obj;
                    callback.onFinish();
                    callback.onFailure(code);
                }
                if (msg.what == CALL_CANCEL) {
                    callback.onFinish();
                    callback.onCancel();
                }
            }
        };


        Request request = new Request.Builder().url(url).build();
        final Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handler.sendEmptyMessage(CALL_FAILURE);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                InputStream is = null;
                FileOutputStream fos = null;
                File saveFile = new File(saveFilePath);
                if (!saveFile.exists()) {
                    saveFile.mkdirs();
                    saveFile.delete();
                } else {
                    saveFile.delete();
                }

                try {

                    is = response.body().byteStream();
                    fos = new FileOutputStream(saveFile);

                    long total = response.body().contentLength();
                    long complete = 0;
                    byte[] buffer = new byte[1024];
                    int readCount;
                    int lastProgress = 0;
                    while ((readCount = is.read(buffer)) != -1) {
                        fos.write(buffer, 0, readCount);
                        complete = readCount + complete;
                        int progress = (int) (1d * complete / total * 100);
                        if (lastProgress != progress) {
                            lastProgress = progress;
                            Message message = handler.obtainMessage();
                            message.what = CALL_RESPONSE_PROGRESS;
                            message.obj = progress;
                            handler.sendMessage(message);
                        }

                    }
                    fos.flush();

                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_PATH;
                    message.obj = saveFile.getAbsolutePath();
                    handler.sendMessage(message);

                } catch (IOException e) {
                    e.printStackTrace();
                    if (saveFile.exists()) {
                        saveFile.delete();
                    }
                    handler.sendEmptyMessage(CALL_CANCEL);

                } finally {
                    try {
                        if (is != null)
                            is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        if (fos != null)
                            fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                if (!response.isSuccessful()) {
                    Message message = handler.obtainMessage();
                    message.what = CALL_RESPONSE_FAILURE;
                    message.obj = response.code();
                    handler.sendMessage(message);
                }
            }
        });

        callback.onStart();
        return call;
    }


    /**
     * 取消所有的网络请求
     */
    public void cancelAll() {
        client.dispatcher().cancelAll();
    }

    public void cancel(Call call) {
        if (call != null) {
            call.cancel();
        }
    }


}
